// ============================================================================
// 通用工具函数
// ============================================================================

const toCamelCase = (str: string) => str.replace(/_([a-zA-Z])/g, (_, letter) => letter.toUpperCase())

const toSnakeCase = (str: string) =>
  str
    .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2')
    .replace(/([a-z\d])([A-Z])/g, '$1_$2')
    .toLowerCase()

const convertKeysToCamelCase = <T>(obj: T, excludeKeys: string[] = ['datasets']): T => {
  if (Array.isArray(obj)) return obj.map(item => convertKeysToCamelCase(item, excludeKeys)) as T
  if (obj !== null && typeof obj === 'object') {
    return Object.keys(obj).reduce((acc: Record<string, any>, key: string) => {
      const typedObj = obj as Record<string, any>
      acc[toCamelCase(key)] = excludeKeys.includes(key) ? typedObj[key] : convertKeysToCamelCase(typedObj[key], excludeKeys)
      return acc
    }, {}) as T
  }
  return obj
}

const convertKeysToSnakeCase = <T>(obj: T): T => {
  if (obj instanceof FormData) {
    const formData = new FormData()
    for (const [key, value] of obj.entries()) {
      formData.append(toSnakeCase(key), value)
    }
    return formData as T
  }
  if (Array.isArray(obj)) return obj.map(item => convertKeysToSnakeCase(item)) as T
  if (obj !== null && typeof obj === 'object') {
    return Object.keys(obj as object).reduce((acc: Record<string, any>, key: string) => {
      const typedObj = obj as Record<string, any>
      acc[toSnakeCase(key)] = convertKeysToSnakeCase(typedObj[key])
      return acc
    }, {}) as T
  }
  return obj
}

// ============================================================================
// LaTeX 格式化辅助函数
// ============================================================================

/** 生成 LaTeX 下标 */
const subscript = (text: string) => `_{${text}}`

/** 生成 LaTeX 上标 */
const superscript = (text: string) => `^{${text}}`

/** 生成 LaTeX 上划线（用于表示反演操作） */
const overline = (text: string) => `\\overline{${text}}`

/**
 * 格式化坐标字符串
 * 使用上划线表示负数（如 1̄ 而不是 -1）
 * @param coords - 坐标字符串，如 "1-10", "-11-1"
 * @returns 格式化后的坐标，如 "1\\overline{1}0", "\\overline{1}1\\overline{1}"
 */
const formatCoords = (coords: string): string => {
  const parts: string[] = []
  let i = 0

  while (i < coords.length) {
    const char = coords[i]
    const nextChar = coords[i + 1]

    if (char === '-' && nextChar && /\d/.test(nextChar)) {
      // 负数：使用上划线
      parts.push(overline(nextChar))
      i += 2
    } else if (char && /\d/.test(char)) {
      parts.push(char)
      i += 1
    } else {
      i += 1
    }
  }

  return parts.join('')
}

// ============================================================================
// 对称性符号格式化函数
// ============================================================================

/**
 * 将 Schoenflies 符号转换为 LaTeX 格式（下标格式）
 * @example "C6v" → "C_{6v}", "D3h" → "D_{3h}", "Td" → "T_{d}"
 */
const formatSchoenflies = (symbol: string) =>
  symbol
    .replace(/^([TOI])([dh])$/i, '$1_{$2}')
    .replace(/^([A-Z])(\d+)([a-z]+)$/i, '$1_{$2$3}')
    .replace(/^([A-Z])([a-z]{2,})$/i, '$1_{$2}')
    .replace(/^([A-Z])(\d+)$/i, '$1_{$2}')
    .replace(/^([A-Z])([a-z])$/i, '$1_{$2}')

/**
 * 将 International 符号转换为 LaTeX 格式（上划线用 \overline）
 * @example "4/m" → "4/m", "-3m" → "\overline{3}m"
 */
const formatInternational = (symbol: string) => symbol.replace(/-(\d)/g, (_, num) => overline(num))

/**
 * 将 Mulliken 符号转换为 LaTeX 格式
 * @example "A1" → "A_{1}", "Eg" → "E_{g}", "1Eu" → "{}^{1}E_{u}", "A'1" → "A^{'}_{1}"
 */
const formatMulliken = (symbol: string): string => {
  // 处理前缀数字（多重态），如 1E, 2Eu → ¹E, ²Eᵤ
  const prefixMatch = symbol.match(/^(\d+)([A-Z].*)$/)
  if (prefixMatch) {
    const [, prefix = '', rest = ''] = prefixMatch
    return `{}${superscript(prefix)}${formatMulliken(rest)}`
  }

  // 处理 prime 符号：检测所有可能的 prime 位置
  if (symbol.includes("'")) {
    // 格式1：A'1, A''2 (prime 在字母后，数字前)
    let match = symbol.match(/^([A-Z])('+)(\d+)([gu]?)$/)
    if (match) {
      const [, letter = '', primes = '', num = '', gu = ''] = match
      let latex = letter + superscript(primes)
      const sub = num + gu
      if (sub) latex += subscript(sub)
      return latex
    }

    // 格式2：A1', Eg' (prime 在最后)
    match = symbol.match(/^([A-Z])(\d*)([gu]?)('+)$/)
    if (match) {
      const [, letter = '', num = '', gu = '', primes = ''] = match
      let latex = letter
      const sub = num + gu
      if (sub) latex += subscript(sub)
      latex += superscript(primes)
      return latex
    }
  }

  // 标准格式复用 Schoenflies 逻辑
  return formatSchoenflies(symbol)
}

/**
 * 将 Gamma 符号转换为 LaTeX 格式
 * @example "Γ1" → "\Gamma_{1}", "Γ2+" → "\Gamma_{2}^{+}", "Γ5-" → "\Gamma_{5}^{-}"
 */
const formatGamma = (symbol: string) => {
  // 匹配 Γ + 数字 + 可选的 +/- 后缀
  const match = symbol.match(/^Γ(\d+)([+-]?)$/)
  if (match) {
    const [, num = '', plusMinus = ''] = match
    let latex = `\\Gamma${subscript(num)}`
    if (plusMinus) latex += superscript(plusMinus)
    return latex
  }
  return symbol
}

/**
 * 将特征值转换为 LaTeX 格式
 * @example "1j" → "i", "-1j" → "-i", "w" → "\omega", "w2" → "\omega^{2}"
 */
const formatCharacter = (char: string) => {
  // Python 虚数单位 1j/-1j → 数学标准 i/-i
  if (char === '1j') return 'i'
  if (char === '-1j') return '-i'

  // Bilbao 的 w/w2 符号 → ω/ω²
  const wMatch = char.match(/^(-?)w(\d?)$/)
  if (wMatch) {
    const [, minus, power] = wMatch
    return power === '2' ? `${minus}\\omega^{2}` : `${minus}\\omega`
  }

  return char
}

// ============================================================================
// 对称操作格式化函数
// ============================================================================

/**
 * 将 ITA（国际晶体学表）符号转换为 LaTeX 格式
 *
 * 支持格式：
 * - 负数直接显示：-1 → "-1"（不用上划线）
 * - 负数带上标：-3+ → "-3^{+}"
 * - 旋转轴带坐标：3+ 0,0,z → "3^{+}\;0,0,z"
 * - 简单符号：2 x,x,0 → "2\;x,x,0"
 *
 * @param symbol ITA 符号
 * @returns LaTeX 格式字符串
 * @example "-1" → "-1", "-3+" → "-3^{+}", "3+ 0,0,z" → "3^{+}\\;0,0,z"
 */
const formatItaSymbol = (symbol: string) => {
  // 处理 "-3+" 格式（负数+上标）
  const negativeWithSuperscript = symbol.match(/^(-\d+)([+-])(.*)$/)
  if (negativeWithSuperscript) {
    const [, base = '', plusMinus = '', rest = ''] = negativeWithSuperscript
    return `${base}${superscript(plusMinus)}${rest ? '\\;' + rest : ''}`
  }

  // 处理 "3+ 0,0,z" 格式（旋转轴带坐标）
  const axisWithCoords = symbol.match(/^(\d+)([+-])\s+(.+)$/)
  if (axisWithCoords) {
    const [, num = '', plusMinus = '', coords = ''] = axisWithCoords
    return `${num}${superscript(plusMinus)}\\;${coords}`
  }

  // 处理简单格式：2 xxx, m xxx（符号后有空格和内容）
  const simpleWithSpace = symbol.match(/^([2m])\s+(.+)$/)
  if (simpleWithSpace) {
    const [, prefix = '', rest = ''] = simpleWithSpace
    return `${prefix}\\;${rest}`
  }

  // 其他情况直接返回（包括 -1, -3, -4, -6 等）
  return symbol
}

/**
 * 将 Seitz 符号转换为 LaTeX 格式
 *
 * 支持格式：
 * - 恒等/反演：1, -1
 * - 旋转（简写）：3+, 3-, 4+, 6-
 * - 旋转反演（简写）：-3+, -3-, -4+, -6-
 * - 旋转（完整）：3+111, 3-001, -3+111
 * - 二重轴（数字）：2001, 21-10, 2-101
 * - 二重轴（字母）：2x, 2y, 2z
 * - 镜面（数字）：m001, m1-10, m-101
 * - 镜面（字母）：mx, my, mz
 *
 * @example "3+" → "3^{+}", "-6-" → "-6^{-}", "m1-10" → "m_{1-10}", "2z" → "2_{z}"
 */
const formatSeitz = (symbol: string) => {
  // 恒等和反演操作直接返回（与 Bilbao 一致）
  if (symbol === '1') return '1'
  if (symbol === '-1') return '-1'

  // 辅助函数：构建 Seitz 格式
  const buildSeitz = (base: string, plusMinus?: string, coords?: string) => {
    let latex = base
    if (plusMinus) latex += superscript(plusMinus)
    if (coords) latex += subscript(formatCoords(coords))
    return latex
  }

  // === 优先匹配二重轴和镜面（避免被旋转操作误匹配）===

  // 二重轴（数字坐标）：2001, 21-10, 2-101
  const c2NumMatch = symbol.match(/^2([\d-]+)$/)
  if (c2NumMatch) {
    const [, coords = ''] = c2NumMatch
    return buildSeitz('2', undefined, coords)
  }

  // 二重轴（字母坐标）：2x, 2y, 2z
  const c2LetterMatch = symbol.match(/^2([xyz])$/)
  if (c2LetterMatch) {
    const [, axis = ''] = c2LetterMatch
    return `2${subscript(axis)}`
  }

  // 镜面（数字坐标）：m001, m1-10, m-101
  const mirrorNumMatch = symbol.match(/^m([\d-]+)$/)
  if (mirrorNumMatch) {
    const [, coords = ''] = mirrorNumMatch
    return buildSeitz('m', undefined, coords)
  }

  // 镜面（字母坐标）：mx, my, mz
  const mirrorLetterMatch = symbol.match(/^m([xyz])$/)
  if (mirrorLetterMatch) {
    const [, axis = ''] = mirrorLetterMatch
    return `m${subscript(axis)}`
  }

  // === 旋转和旋转反演操作 ===

  // 旋转/旋转反演（简写）：3+, 3-, -3+, -3-, -6+, -6-
  // 注意：前面的 - 表示旋转反演操作，不用 overline，直接显示
  const simpleMatch = symbol.match(/^(-?)(\d+)([+-])$/)
  if (simpleMatch) {
    const [, minus = '', num = '', plusMinus = ''] = simpleMatch
    return buildSeitz(minus + num, plusMinus)
  }

  // 旋转/旋转反演（完整）：3+111, 3-001, -3+111, -6-111
  const fullMatch = symbol.match(/^(-?)(\d+)([+-])([\d-]+)$/)
  if (fullMatch) {
    const [, minus = '', num = '', plusMinus = '', coords = ''] = fullMatch
    return buildSeitz(minus + num, plusMinus, coords)
  }

  // 旋转反演（无上标，带坐标）：-4001, -3001
  const barMatch = symbol.match(/^-(\d+)([\d-]+)$/)
  if (barMatch) {
    const [, num = '', coords = ''] = barMatch
    return buildSeitz('-' + num, undefined, coords)
  }

  return symbol
}

export const convertPi = (text: string) => text.replace(/π(?=[a-zA-Z])/g, '\\pi ').replace(/π/g, '\\pi')

// ============================================================================
// 导出
// ============================================================================

export { convertKeysToCamelCase, convertKeysToSnakeCase, formatCharacter, formatGamma, formatInternational, formatItaSymbol, formatMulliken, formatSchoenflies, formatSeitz, toCamelCase, toSnakeCase }
